package com.scanner;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.Toast;

public class MainScannerActivity extends Activity {

	
	ScannerGraphics graphicsSurfaceView;
	
	CameraPreview cameraPreview;
    FrameLayout alParent;
    CharSequence topLeftText = "toast! top left corner";
    CharSequence startText = "preview started";
    CharSequence endText = "preview ended";
    Toast toast, startPreviewToast, endPreviewToast;
 
    public static final int MEDIA_TYPE_IMAGE = 1;
    public static final int MEDIA_TYPE_VIDEO = 2;
    public int size = 60;   
	public static boolean setAFon = true;
	public static int wait4nextAF = 100;
	public static int[] testjpg;
	public static Context mContext;
	public static boolean running;  
	TakePictureSeries mTakePictureSeries;
	
	DebugView debugView;
	String procMethod;
    
    
    @SuppressLint("ShowToast")
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mContext = this;
        
        // Set the screen orientation to landscape, because 
        // the camera preview will be in landscape, and if we 
        // don't do this, then we will get a stretched image.
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
 
        // requesting to turn the title OFF
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        Window window = getWindow();
        // making it full screen
        window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        window.setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, 128);
        
        graphicsSurfaceView = new ScannerGraphics(this);
        
        toast = Toast.makeText(getApplicationContext(), topLeftText, Toast.LENGTH_SHORT);
        startPreviewToast = Toast.makeText(getApplicationContext(), startText, Toast.LENGTH_LONG);
        endPreviewToast = Toast.makeText(getApplicationContext(), endText, Toast.LENGTH_LONG);
        running = false;
        
        graphicsSurfaceView.SetEventObserver(new ScannerEventListener(){
        	@Override
			public void ScannerEventCallback(boolean flag, String method)
        	{
        		graphicsSurfaceView.captureButton.setStateEnabled(flag);
        	}
        });
        
    }
 
    
    //Menu handling
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    	
        // Handle item selection
        switch (item.getItemId()) {
            case R.id.scan:
            	if(!running)
  		        {
  		          Log.d("myLog", "start button, start running");
  		          running = true;
  		          takePictureSeriesInit();
  		          mTakePictureSeries.start();
  		          startPreviewToast.show();
  		        }//App stopped      
        		graphicsSurfaceView.invalidate();
                return true;
            case R.id.stop:
            	if(running){
  		          Log.d("myLog", "start button, stop running");
  		          running = false;
  		          mTakePictureSeries.StopRunning();  
  		          endPreviewToast.show();
  		        }//App started  		              
        		graphicsSurfaceView.invalidate();
            	return true;
            case R.id.flash:
            	ToggleFlash();
            	return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
    //Menu handling
    
    private void ToggleFlash()
    {    	
    	cameraPreview.ToggleFlash();
    }
    
    public void Load(){
        // Try to get the camera 
        Camera cam = getCameraInstance();
 
        // If the camera was received, create the app
        if (cam != null){
            // Create our layout in order to layer the 
            // draw view on top of the camera preview. 
            alParent = new FrameLayout(this);
            alParent.setLayoutParams(new LayoutParams(
                LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT));
 
            // Create a new camera view and add it to the layout
            cameraPreview = new CameraPreview(this,cam);
            alParent.addView(cameraPreview);
            // Create a new draw view and add it to the layout
            
            alParent.addView(graphicsSurfaceView);
            
            // Set the layout as the apps content view 
            setContentView(alParent);
        }
        // If the camera was not received, close the app
        else {
            Toast toast = Toast.makeText(getApplicationContext(), 
                "Unable to find camera. Closing.", Toast.LENGTH_SHORT);
            toast.show();
            finish();
        }
    }
 
    // This method is strait for the Android API 
    // A safe way to get an instance of the Camera object. 
    public static Camera getCameraInstance(){
        Camera c = null; 
        try {
            c = Camera.open();// attempt to get a Camera instance
        }
        catch (Exception e){
            // Camera is not available (in use or does not exist)
            e.printStackTrace();
        }
        return c; // returns null if camera is unavailable
    }
 
    // Override the onPause method so that we 
    // can release the camera when the app is closing. 
    @Override
    protected void onPause() {
        super.onPause();
 
        if (cameraPreview != null){
            cameraPreview.onPause();
            cameraPreview = null;
        }
    }
 
    // We call Load in our Resume method, because 
    // the app will close if we call it in onCreate
    @Override
    protected void onResume(){
        super.onResume();
        Load();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
    	CenterButton cButton = graphicsSurfaceView.captureButton;
    	if (event.getAction()==MotionEvent.ACTION_DOWN && cButton.isStateEnabled())
    	{
	    	Point touchPoint = new Point((int)event.getX(),(int)event.getY());
	    	if (cButton.IsHit(touchPoint.x, touchPoint.y))
	    	{
	    		cameraPreview.ScanPicture(shutterCallback,mPicture);
	    		return true;
	    	}
    	}
    	return false;
    }
	private void takePictureSeriesInit()
	{
        mTakePictureSeries = new TakePictureSeries(cameraPreview);
        mTakePictureSeries.StartRunning();
        mTakePictureSeries.SetEventObserver(new ScannerEventListener(){
        	@Override
			public void ScannerEventCallback(boolean foundPoints, String method)
        	{
        		procMethod = mTakePictureSeries.getProcMethod();
        		if (foundPoints)
        		{
	        		graphicsSurfaceView.UpdateContour(mTakePictureSeries.recievedPoints);  
        		}
        		else
        		{
        			graphicsSurfaceView.ClearView();
        			graphicsSurfaceView.captureButton.setStateEnabled(false);
        		}   
        		graphicsSurfaceView.UpdateText(method);
        		graphicsSurfaceView.invalidate();
        	}
        });
	}
  ShutterCallback shutterCallback = new ShutterCallback() {
        public void onShutter() {
        }
  };
    
  PictureCallback mPicture = new PictureCallback() {

      public void onPictureTaken(byte[] data, Camera camera) {
    	  int[] cropPoints = GetCropPoints();
          File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
          FileOutputStream fos;
          if (pictureFile == null){
              Log.d("myErr", "Error creating media file, check storage permissions: ");
              return;
          }
          try {
              fos = new FileOutputStream(pictureFile);
              fos.write(data);
              fos.close();
              Log.d("debug", "onPictureTaken finished");
          } catch (FileNotFoundException e) {
              Log.d("myErr", "File not found: " + e.getMessage());
          } catch (IOException e) {
              Log.d("myErr", "Error accessing file: " + e.getMessage());
          }          
          try {
        	  ByteArrayInputStream imageStream = new ByteArrayInputStream(data);
        	  Bitmap inImage = BitmapFactory.decodeStream(imageStream);
        	  Bitmap croppedBmp = Bitmap.createBitmap(inImage,cropPoints[0],cropPoints[1],cropPoints[2],cropPoints[3]);
        	  pictureFile = getCroppedOutputMediaFile(MEDIA_TYPE_IMAGE);
              fos = new FileOutputStream(pictureFile);
              croppedBmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
              fos.write(data);
              fos.close();
              Log.d("debug", "onPictureTaken finished");
          } catch (FileNotFoundException e) {
              Log.d("myErr", "File not found: " + e.getMessage());
          } catch (IOException e) {
              Log.d("myErr", "Error accessing file: " + e.getMessage());
          }       
          sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
      }
  };
    
  @SuppressWarnings("static-access")
private int[] GetCropPoints()
  {
	  if (mTakePictureSeries.cachedRecievedPoints == null || mTakePictureSeries.cachedRecievedPoints.length != 8)
	  {
		  return null;
	  }
	  
	  int[] cropCoord = new int[4];
	  cropCoord[0] = Math.max(mTakePictureSeries.cachedRecievedPoints[0] , mTakePictureSeries.cachedRecievedPoints[6]);
	  cropCoord[1] = Math.max(mTakePictureSeries.cachedRecievedPoints[1] , mTakePictureSeries.cachedRecievedPoints[3]);
	  cropCoord[2] = Math.min(mTakePictureSeries.cachedRecievedPoints[2] , mTakePictureSeries.cachedRecievedPoints[4]) - cropCoord[0];
	  cropCoord[3] = Math.min(mTakePictureSeries.cachedRecievedPoints[5] , mTakePictureSeries.cachedRecievedPoints[7]) - cropCoord[1];
	  
	  return cropCoord;
  }
  
  /** Create a File for saving an image or video */
  @SuppressLint("SimpleDateFormat")
private static File getOutputMediaFile(int type){
      // To be safe, you should check that the SDCard is mounted
      // using Environment.getExternalStorageState() before doing this.

      File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), "MyScanerApp");
      // This location works best if you want the created images to be shared
      // between applications and persist after your app has been uninstalled.

      // Create the storage directory if it does not exist
      if (! mediaStorageDir.exists()){
          if (! mediaStorageDir.mkdirs()){
              Log.d("MyScanerApp", "failed to create directory");
              return null;
          }
      }

      // Create a media file name
      String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
      File mediaFile;
      if (type == MEDIA_TYPE_IMAGE){
          mediaFile = new File(mediaStorageDir.getPath() + File.separator +
          "SCAN_"+ timeStamp + ".jpg");
      } else if(type == MEDIA_TYPE_VIDEO) {
          mediaFile = new File(mediaStorageDir.getPath() + File.separator +
          "VID_"+ timeStamp + ".mp4");
      } else {
          return null;
      }

      return mediaFile;
  }
  
  @SuppressLint("SimpleDateFormat")
@SuppressWarnings("unused")
private static File getCroppedOutputMediaFile(int type){
      // To be safe, you should check that the SDCard is mounted
      // using Environment.getExternalStorageState() before doing this.

      File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), "MyScanerApp");
      // This location works best if you want the created images to be shared
      // between applications and persist after your app has been uninstalled.

      // Create the storage directory if it does not exist
      if (! mediaStorageDir.exists()){
          if (! mediaStorageDir.mkdirs()){
              Log.d("MyScanerApp", "failed to create directory");
              return null;
          }
      }

      // Create a media file name
      String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
      File mediaFile;
      if (type == MEDIA_TYPE_IMAGE){
          mediaFile = new File(mediaStorageDir.getPath() + File.separator +
          "SCAN_CROP_"+ timeStamp + ".jpg");
      } else if(type == MEDIA_TYPE_VIDEO) {
          mediaFile = new File(mediaStorageDir.getPath() + File.separator +
          "VID_CROP_"+ timeStamp + ".mp4");
      } else {
          return null;
      }

      return mediaFile;
  }
  
}